﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace PKSpeed
{
    /// <summary>
    /// 命令的解析、执行
    /// </summary>
    public class PKCommand
    {
        /// <summary>
        /// 当前用户
        /// </summary>
        public String CurrentUser { get; set; }
        /// <summary>
        /// 当前工作目录
        /// </summary>
        public String CurrentPath { get; set; }
        /// <summary>
        /// 历史命令
        /// </summary>
        public String[] HistoryInput { get; set; }
        /// <summary>
        /// 历史命令游标
        /// </summary>
        public int HistoryInputPointer { get; set; }

        /// <summary>
        /// 用户当前输入
        /// </summary>
        public string CurrentInput { get; set; }

        /// <summary>
        /// 命令类型
        /// </summary>
        public String CommandName { get; set; }
        /// <summary>
        /// 命令参数
        /// </summary>
        public String CommandArg { get; set; }
        /// <summary>
        /// 操作参数
        /// </summary>
        public List<String> Args { get; set; }
        /// <summary>
        /// 重定向目的输出文件
        /// </summary>
        public String OutFileName { get; set; }
        /// <summary>
        /// 管道机制grep实现的参数
        /// </summary>
        public List<String> GrepArgs { get; set; }
        /// <summary>
        /// 操作委托
        /// </summary>
        /// <param name="commandArg">命令参数</param>
        /// <param name="args">操作参数</param>
        /// <param name="outFileName">重定向目的输出文件</param>
        /// <param name="grepArg">管道机制grep实现的参数</param>
        /// <returns>命令执行结果</returns>
        public delegate bool Operation(String commandArg, List<String> args, String outFileName, List<String> grepArg);
        /// <summary>
        /// 委托对象
        /// </summary>
        public Operation Operator { get; set; }

        /// <summary>
        /// 初始化
        /// </summary>
        public PKCommand()
        {
            CurrentPath = "/";
            HistoryInput = new String[11];
            HistoryInputPointer = 0;
        }

        /// <summary>
        /// 解析用户输入的指令
        /// </summary>
        /// <param name="commandStr">用户输入的命令字符串</param>
        /// <returns>是否成功</returns>
        public bool Start(String commandStr)
        {
            //初始化，以防止误用上次的结果
            CommandName = null;
            CommandArg = null;
            Args = new List<string>();
            OutFileName = null;
            GrepArgs = new List<string>();
            CurrentInput = commandStr;
            //使用有穷自动机进行解析，一次遍历得到结果，以提高效率
            String token = ""; //识别出的单个单词
            int p = 0; //源串游标
            char c = commandStr[p++];//当前读入的字符

            while (c == ' ' && p != commandStr.Length) //忽略重复的空格
            {
                c = commandStr[p++];
            }
            if (c == ' ' && p == commandStr.Length)
            {
                return true;
            }
            while (c != ' ') //命令的名称
            {
                token += c;
                if (p == commandStr.Length) //字符串已经结束
                {
                    break;
                }
                c = commandStr[p++];
            }
            if (HashCommand.GetHashCode(token) == -1) //如果没有这个命令，错误
            {
                Console.WriteLine("不存在该命令！");
                return false;
            }
            CommandName = token;

            while (c == ' ' && p != commandStr.Length) //忽略重复的空格
            {
                c = commandStr[p++];
            }

            if (CommandName == "alias")//如果是Alias命令，则直接将后边的参数放入参数中
            {
                Args.Add(commandStr.Substring(p - 1));
                return true;
            }

            if ((c == '-' || c == '|' || c == '>') && p == commandStr.Length) //不应该结束，错误
            {
                Console.WriteLine("错误的命令格式！");
                return false;
            }

            while (p != commandStr.Length) //获取后边的参数
            {
                token = "";
                switch (c)
                {
                    case '-':
                        c = commandStr[p++];
                        if (CommandArg != null //如果已经有命令参数，错误
                            || c == ' ' //如果没有命令参数时后边不是命令参数，错误
                            || !GetArgStr(ref token, ref c, commandStr, ref p, false)) //获取命令参数失败，错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        if (token == "name" && Args.Count == 0)
                        {
                            Args.Add(".");//默认为当前目录
                        }
                        if(token == "name" && Args.Count > 1)//find命令格式错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        CommandArg = token;
                        break;
                    case '>':
                        c = commandStr[p++];
                        if (OutFileName != null //如果已经有重定向参数，错误
                            || c != ' ') //如果没有重定向参数时，后边不是空格，错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        while (c == ' ' && p != commandStr.Length) //忽略多余的空格
                        {
                            c = commandStr[p++];
                        }
                        if (c == ' ' && p == commandStr.Length)//不应该结束，错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        if (!GetArgStr(ref token, ref c, commandStr, ref p, false)) //如果获取参数失败，错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        OutFileName = token;
                        break;
                    case '|':
                        c = commandStr[p++];
                        if (c != ' ') //如果后边不是空格，错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        while (c == ' ' && p != commandStr.Length) //忽略多余的空格
                        {
                            c = commandStr[p++];
                        }
                        if (c != 'g' || (p != commandStr.Length && commandStr[p++] != 'r') ||
                            (p != commandStr.Length && commandStr[p++] != 'e')
                            || (p != commandStr.Length && commandStr[p++] != 'p') ||
                            (p != commandStr.Length && commandStr[p++] != ' ') || p == commandStr.Length) //如果不是"grep ",错误
                        {
                            while(c != '|' && c != '>')
                            {
                                c = commandStr[p++];
                                if(p == commandStr.Length)
                                {
                                    Console.WriteLine("通道中出现无意义的命令，已经忽略！");
                                    return true;
                                }
                            }
                            break;
                        }
                        c = commandStr[p++];
                        while (c == ' ' && p != commandStr.Length)//忽略多余的空格
                        {
                            c = commandStr[p++];
                        }
                        if (c == ' ' && p == commandStr.Length)//不应该结束，错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        if (!GetArgStr(ref token, ref c, commandStr, ref p, true)) //如果获取参数失败，错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        GrepArgs.Add(token);
                        break;
                    default:
                        if (!GetArgStr(ref token, ref c, commandStr, ref p, true)) //如果获取参数失败，错误
                        {
                            Console.WriteLine("错误的命令格式！");
                            return false;
                        }
                        Args.Add(token);
                        break;
                }
                while (c == ' ' && p != commandStr.Length) //忽略多余的空格
                {
                    c = commandStr[p++];
                }
            }
            if (c == '-' || c == '|' || c == '>') //不应该结束，错误
            {
                Console.WriteLine("错误的命令格式！");
                return false;
            }
            if (c != ' ' && p - 3 >= 0 && commandStr[p - 2] == ' ' && commandStr[p - 3] != '>'
                && (p - 8 < 0 || p - 8 >= 0 && commandStr[p - 8] != '|'))//仅仅有一个字符的参数
            {
                Args.Add(c.ToString());
            }
            if(CommandName == "find" && Args.Count == 0)
            {
                Args.Add(".");
            }
            return true;
        }

        /// <summary>
        /// 将命令对应到相应的操作方法
        /// </summary>
        /// <returns>是否成功</returns>
        public bool Get()
        {
            try
            {
                Operator = HashCommand.Operators[HashCommand.GetHashCode(CommandName)];
                return true;
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <returns>执行结果</returns>
        public bool Execute()
        {
            try
            {
                ErrorLog.OperationStart();//将当前命令写入配置文件
                bool result= Operator(CommandArg, Args, OutFileName, GrepArgs);
                ErrorLog.OperationEnd();//将当前命令移出配置文件
                return result;
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }
        }

        //获取参数字符串
        private static bool GetArgStr(ref String token, ref char c, String sourceStr, ref int p, bool flag)
        {
            while (c != ' ') //获取参数
            {
                if (!flag && (c == '|' || c == '>' || c == '-')) //错误的参数
                {
                    Console.WriteLine("错误的命令格式！");
                    return false;
                }
                token += c;
                if (p == sourceStr.Length) //字符串已经结束
                {
                    break;
                }
                c = sourceStr[p++];
            }
            if (p != sourceStr.Length && c != ' ') //如果后边不是结尾并且不是空格，错误
            {
                Console.WriteLine("错误的命令格式！");
                return false;
            }
            return true;
        }
    }
}
